<template>
  <el-container style="height:800px">
    <el-main style="display:flex;border: 1px solid #dfe3e8;height:600px">
        <div id="stencil" style=" width: 180px;height: 100%;position: relative;border-right: 1px solid #dfe3e8;"></div>
        <div id="graph-container" style="width: calc(100% - 180px); height: 100%;"></div>
    </el-main>
    <el-aside width="200px">
         <div><el-input v-model="state.nodeData.name" placeholder="节点名称"></el-input></div>
         
        
    </el-aside>
  </el-container>

</template>

<script lang="ts">
   export default { name: 'xflow'};  
 </script>

<script setup lang="ts">
  import { reactive, ref, watch, onMounted, toRefs } from 'vue'
  import { Graph, Shape, Addon } from '@antv/x6'

  const state = reactive({
        curentNode:{},
        nodeData:{}
  });
   

  function initFlow(){
      //初始化画布
      let graph = initGraph();
      //初始化工具栏
      let stencil= initStencil(graph);
      //设置连线点
      let ports=setPorts(); 
      //配置新节点
      registerNode(ports);
      //工具栏加入工具图
      stencilLoad(stencil,graph);
      //连线节点事件
      nodePortsEvent(graph,ports); 
      //快捷键事件
      ctrlEvent(graph);
      //节点、连线点击事件
      nodeEdgeEvent(graph);
      
  }
  function initGraph(){
    let graph = new Graph({
        container: document.getElementById('graph-container'),
        grid: true,
        mousewheel: {
          enabled: true,
          zoomAtMousePosition: true,
          modifiers: 'ctrl',
          minScale: 0.5,
          maxScale: 3,
        },
        connecting: {
          router: {
            name: 'manhattan',
            args: {
              padding: 1,
            },
          },
          connector: {
            name: 'rounded',
            args: {
              radius: 8,
            },
          },
          anchor: 'center',
          connectionPoint: 'anchor',
          allowBlank: false,
          snap: {
            radius: 20,
          },
          createEdge() {
            return new Shape.Edge({
              attrs: {
                line: {
                  stroke: '#A2B1C3',
                  strokeWidth: 2,
                  targetMarker: {
                    name: 'block',
                    width: 12,
                    height: 8,
                  },
                },
              },
              tools: [
                {
                  name: 'button',
                  args: {
                    markup: [
                      {
                        tagName: 'circle',
                        selector: 'button',
                        attrs: {
                          r: 12,
                          stroke: '#fe854f',
                          strokeWidth: 3,
                          fill: 'white',
                          cursor: 'pointer',
                        },
                      },
                      {
                        tagName: 'text',
                        textContent: '+',
                        selector: 'icon',
                        attrs: {
                          fill: '#fe854f',
                          fontSize: 20,
                          textAnchor: 'middle',
                          pointerEvents: 'none',
                          y: '0.3em',
                        },
                      },
                    ],
                    distance: 0.5,
                    onClick({ view }: any) {
                      const edge = view.cell
                      const source = edge.getSource()
                      const target = edge.getTarget()
                      alert("添加节点");
                    },
                  },
                },
              ],
              zIndex: 0,
            })
          },
          validateConnection({ targetMagnet }) {
            return !!targetMagnet
          },
        },
        highlighting: {
          magnetAdsorbed: {
            name: 'stroke',
            args: {
              attrs: {
                fill: '#5F95FF',
                stroke: '#5F95FF',
              },
            },
          },
        },
        resizing: false,
        rotating: false,
        selecting: {
          enabled: true,
          rubberband: true,
          showNodeSelectionBox: true,
        },
        snapline: true,
        keyboard: true,
        clipboard: true,
    });


      
      return graph;
  }

  function initStencil(graph){
    let stencil = new Addon.Stencil({
        title: '流程图',
        target: graph,
        stencilGraphWidth: 200,
        stencilGraphHeight: 180,
        collapsable: true,
        groups: [
          {
            title: '基础流程图',
            name: 'group1',
          },
          {
            title: '系统设计图',
            name: 'group2',
            graphHeight: 250,
            layoutOptions: {
              rowHeight: 70,
            },
          },
        ],
        layoutOptions: {
          columns: 2,
          columnWidth: 80,
          rowHeight: 55,
        },
      });
    document.getElementById('stencil')!.appendChild(stencil.container)
    return stencil;
  }

  function setPorts(){
    let ports = {
      groups: {
        top: {
          position: 'top',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        right: {
          position: 'right',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        bottom: {
          position: 'bottom',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
        left: {
          position: 'left',
          attrs: {
            circle: {
              r: 4,
              magnet: true,
              stroke: '#5F95FF',
              strokeWidth: 1,
              fill: '#fff',
              style: {
                visibility: 'hidden',
              },
            },
          },
        },
      },
      items: [
        {
          group: 'top',
        },
        {
          group: 'right',
        },
        {
          group: 'bottom',
        },
        {
          group: 'left',
        },
      ],
    }
    return ports;
  }
  function registerNode(ports){
      Graph.registerNode(
          'event',
          {
            inherit: 'circle',
            width: 40,
            height: 40,
            attrs: {
              body: {
                strokeWidth: 2,
                stroke: '#5F95FF',
                fill: '#FFF',
              },
            },
            ports: { ...ports },
          },
          true,
        )
        Graph.registerNode(
        'gateway',
        {
          inherit: 'polygon',
          attrs: {
            body: {
              refPoints: '0,10 10,0 20,10 10,20',
              strokeWidth: 2,
              stroke: '#5F95FF',
              fill: '#EFF4FF',
            },
            label: {
              text: '+',
              fontSize: 40,
              fill: '#5F95FF',
            },
          },
            ports: { ...ports },
        },
        true,
      )
      Graph.registerNode(
        'activity',
        {
          inherit: 'rect',
          width: 100,
          height: 60,
          markup: [
            {
              tagName: 'rect',
              selector: 'body',
            },
            {
              tagName: 'image',
              selector: 'img',
            },
            {
              tagName: 'text',
              selector: 'label',
            },
          ],
          attrs: {
            body: {
              rx: 6,
              ry: 6,
              stroke: '#5F95FF',
              fill: '#EFF4FF',
              strokeWidth: 1,
            },
            img: {
              x: 6,
              y: 6,
              width: 16,
              height: 16,
              'xlink:href':
                'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*pwLpRr7QPGwAAAAAAAAAAAAAARQnAQ',
            },
            label: {
              fontSize: 12,
              fill: '#262626',
            },
          },
            ports: { ...ports },
        },
        true,
      )
  }

  function stencilLoad(stencil,graph){
      const s1 = graph.createNode({
        "shape": "event",
        "position": {
          "x": 50,
          "y": 180
        },
        "data":{
          "type":1,
          "name":"开始"
        }
      })

      const s4 = graph.createNode({
          "shape": "event",
          "position": {
            "x": 710,
            "y": 290
          },
          "attrs": {
            "body": {
              "strokeWidth": 6
            }
          },
          "data":{
            "type":2,
            "name":"开始"
          }
      })

        
      const s2 = graph.createNode({
          "shape": "gateway",
          "width": 55,
          "height": 55,
          "position": {
            "x": 170,
            "y": 282.5
          },
          "data":{
            "type": 2,
            "name":"条件"
          }
      })
      const s3 = graph.createNode({
          "shape": "activity",
          "position": {
            "x": 300,
            "y": 240
          },
          "label": "事务",
          "data":{
            "type":3,
            "name":"事务"
          }
      })

      stencil.load([s1,s4,s2], 'group1')
      stencil.load([s3,], 'group2')
  }

  function ctrlEvent(graph){
      // #region 快捷键与事件
    // copy cut paste
    graph.bindKey(['meta+c', 'ctrl+c'], () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.copy(cells)
      }
      return false
    })
    graph.bindKey(['meta+x', 'ctrl+x'], () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.cut(cells)
      }
      return false
    })
    graph.bindKey(['meta+v', 'ctrl+v'], () => {
      if (!graph.isClipboardEmpty()) {
        const cells = graph.paste({ offset: 32 })
        graph.cleanSelection()
        graph.select(cells)
      }
      return false
    })

    //undo redo
    graph.bindKey(['meta+z', 'ctrl+z'], () => {
      if (graph.history.canUndo()) {
        graph.history.undo()
      }
      return false
    })
    graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
      if (graph.history.canRedo()) {
        graph.history.redo()
      }
      return false
    })

    // select all
    graph.bindKey(['meta+a', 'ctrl+a'], () => {
      const nodes = graph.getNodes()
      if (nodes) {
        graph.select(nodes)
      }
    })

    //delete
    graph.bindKey('backspace', () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.removeCells(cells)
      }
    })

    // zoom
    graph.bindKey(['ctrl+1', 'meta+1'], () => {
      const zoom = graph.zoom()
      if (zoom < 1.5) {
        graph.zoom(0.1)
      }
    })
    graph.bindKey(['ctrl+2', 'meta+2'], () => {
      const zoom = graph.zoom()
      if (zoom > 0.5) {
        graph.zoom(-0.1)
      }
    })
  }
  
  function nodePortsEvent(graph,ports){
      // 控制连接桩显示/隐藏
      const showPorts = (ports: NodeListOf<SVGElement>, show: boolean) => {
        for (let i = 0, len = ports.length; i < len; i = i + 1) {
          ports[i].style.visibility = show ? 'visible' : 'hidden'
        }
      }

       graph.on('edge:mouseenter', ({ cell }) => {
        cell.addTools(
          [
            { name: 'vertices' },
            {
              name: 'button-remove',
              args: { distance: 20  },
            },
          ],
        )
      })

      graph.on('edge:mouseleave', ({ cell }) => {
        if (cell.hasTool('button-remove')) {
          cell.removeTool('button-remove')
        }
      })


      graph.on('node:mouseenter', ({ node }) => {
        const container = document.getElementById('graph-container')!
        const ports = container.querySelectorAll(
          '.x6-port-body',
        ) as NodeListOf<SVGElement>
        showPorts(ports, true);

        node.addTools({
          name: 'button-remove',
          args: {
            x: 0,
            y: 0,
            offset: { x: 10, y: 10 },
          },
        });
      })
      graph.on('node:mouseleave', ({ node }) => {
        const container = document.getElementById('graph-container')!
        const ports = container.querySelectorAll(
          '.x6-port-body',
        ) as NodeListOf<SVGElement>
        showPorts(ports, false)
        node.removeTools()
      })

     

      graph.on('node:click', ({ node }) => {
        state.curentNode = node;
        state.nodeData=node.data;
        node.attr('body/stroke', 'orange');
        console.log(node);
        node.removeTools()
    })
  }

  function nodeEdgeEvent(graph){
    

  }

  onMounted(() =>{
    initFlow();
  });

  watch(() => state.nodeData.name,
      // 回调函数 callback
      (newValue, oldValue) => {
        state.curentNode.label =  newValue;
      }, {immediate:true, deep: true}
  );
</script>


<style lang="scss" scoped>
    .mui-content {
      touch-action: none;
    }
    .x6-widget-stencil  {
      background-color: #fff;
    }
    .x6-widget-stencil-title {
      background-color: #fff;
    }
    .x6-widget-stencil-group-title {
      background-color: #fff !important;
    }
    .x6-widget-transform {
      margin: -1px 0 0 -1px;
      padding: 0px;
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div {
      border: 1px solid #239edd;
    }
    .x6-widget-transform > div:hover {
      background-color: #3dafe4;
    }
    .x6-widget-transform-active-handle {
      background-color: #3dafe4;
    }
    .x6-widget-transform-resize {
      border-radius: 0;
    }
    .x6-widget-selection-inner {
      border: 1px solid #239edd;
    }
    .x6-widget-selection-box {
      opacity: 0;
    }
</style>